package org.lcc.Controller;

import org.lcc.Service.UserService;
import org.lcc.model.VO.UserDtoVO;
import org.lcc.model.dto.*;
import org.lcc.model.entity.BusinessException;
import org.lcc.util.ApiResponseMe;
import org.lcc.util.ParseExcelUtil;
import org.lcc.util.VerifyCodeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;











import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户控制器类，处理用户登录、注册、班级管理、学生管理等请求
 */
@RestController
@RequestMapping
@Tag(name = "用户管理", description = "用户相关的接口，包括登录、注册、班级管理、学生管理等")
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 用户登录接口
     *
     * @param request 登录请求，包含用户名、密码和验证码
     * @return 登录响应，包含用户信息和 Token
     */
    @Operation(summary = "用户登录", description = "用户登录接口，验证用户名、密码和验证码")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "登录成功"),
        @ApiResponse(responseCode = "400", description = "用户名或密码错误")
    })
    @PostMapping("/nerv/login")
    public ApiResponseMe login(
            @Parameter(description = "登录请求，包含用户名、密码和验证码", required = true)
            @RequestBody LoginRequest request) {
        // 参数校验
        if (request == null || request.getUsername() == null || request.getPassword() == null || request.getVerifyCode() == null) {
            throw new BusinessException(400, "用户名或密码不能为空");
        }
        // 查询用户信息
        UserDto user = userService.login(request);
        System.out.println(user.toString());
        if (user == null) {
            throw new BusinessException(400, "用户名或密码错误");
        }
        return ApiResponseMe.success(user);
    }

    /**
     * 验证码生成接口
     *
     * @return 返回验证码图片的二进制流，并在响应头中返回验证码的唯一标识
     */
    @Operation(summary = "获取验证码", description = "生成并返回验证码图片")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/nerv/code")
    public ResponseEntity<byte[]> getCode() {
        try {
            // 生成验证码图片
            VerifyCodeUtils verifyCodeUtils = new VerifyCodeUtils();
            BufferedImage image = verifyCodeUtils.getImage();
            String codeText = verifyCodeUtils.getText();
            System.out.println(codeText);
            // 随机生成一个唯一键（UUID）用于存储验证码文本
            String key = java.util.UUID.randomUUID().toString();

            // 将验证码文本存储到 Redis 中，并设置过期时间为 3 分钟
            redisTemplate.opsForValue().set(key, codeText, 3, TimeUnit.MINUTES);
            // 将图片转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "JPEG", baos);
            byte[] imageBytes = baos.toByteArray();

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.IMAGE_JPEG);
            headers.setContentLength(imageBytes.length);

            // 返回验证码图片，并将 key 作为响应头返回
            headers.add("verifyCode", key); // 将 key 添加到响应头中
            return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 用户注册接口
     *
     * @param signInRequest 注册请求，包含用户信息和加密后的密码
     * @return 注册响应，表示注册结果
     */
    @Operation(summary = "用户注册", description = "新用户注册接口")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "注册成功"),
        @ApiResponse(responseCode = "400", description = "注册信息不完整")
    })
    @PostMapping("/nerv/signin")
    public ApiResponseMe signin(
            @Parameter(description = "注册请求，包含用户信息和加密后的密码", required = true)
            @RequestBody Sign_inRequest signInRequest) {
        if (signInRequest == null || signInRequest.getUsername() == null ||
                signInRequest.getPassword() == null || signInRequest.getRole() == null ||
                signInRequest.getSchool_number() == null || signInRequest.getVerifyCode() == null) {
            throw new BusinessException(400, "注册所需信息不完整");
        }
        return ApiResponseMe.shape(userService.signin(signInRequest), "注册成功");
    }

    /**
     * 忘记密码接口
     *
     * @param signInRequest 包含用户名、学号/工号、新密码和验证码
     * @return 返回密码重置结果
     */
    @Operation(summary = "忘记密码", description = "重置用户密码")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "重置成功"),
        @ApiResponse(responseCode = "400", description = "信息不完整或验证失败")
    })
    @PostMapping("/nerv/test")
    public ApiResponseMe forget(
            @Parameter(description = "包含用户名、学号/工号、新密码和验证码", required = true)
            @RequestBody Sign_inRequest signInRequest) {
        if (signInRequest == null || (signInRequest.getUsername() == null && signInRequest.getSchool_number() == null) || signInRequest.getVerifyCode() == null) {
            throw new BusinessException(400, "信息不全请检查");
        }
        // 通过用户名和学号/工号查询用户
        Boolean forget = userService.forget(signInRequest.getSchool_number(), signInRequest.getUsername(), signInRequest.getPassword(), signInRequest.getVerifyCode(), signInRequest.getVerifyCodeKey());
        if (!forget) {
            return ApiResponseMe.shape(false, "身份验证未通过");
        }
        return ApiResponseMe.shape(forget, "密码重置成功");
    }

    /**
     * 创建班级接口
     *
     * @param createRequest 包含班级名称和老师工号
     * @return 返回创建班级结果
     */
    @Operation(summary = "创建班级", description = "教师创建新班级")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "创建成功"),
        @ApiResponse(responseCode = "400", description = "缺少必要信息")
    })
    @PostMapping("/createClass")
    public ApiResponseMe createClass(
            @Parameter(description = "包含班级名称和老师工号", required = true)
            @RequestBody CreateRequest createRequest) {
        if (createRequest == null || createRequest.getClassname() == null || createRequest.getTeacherNumber() == null) {
            throw new BusinessException(400, "缺少班级名或者老师工号");
        }
        return ApiResponseMe.shape(userService.createClass(createRequest), "创建班级成功");
    }

    /**
     * 批量导入学生接口
     *
     * @param file Excel 文件
     * @param classId 班级 ID
     * @return 返回批量导入结果
     */
    @Operation(summary = "批量导入学生", description = "通过Excel文件批量导入学生信息")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "导入成功"),
        @ApiResponse(responseCode = "400", description = "文件为空或解析失败")
    })
    @PostMapping("/importExcel")
    public ApiResponseMe uploadFile(
            @Parameter(description = "Excel文件", required = true)
            @RequestParam("excelFile") MultipartFile file,
            @Parameter(description = "班级ID", required = true)
            @RequestParam("ClassId") Integer classId) {
        boolean result = false;
        if (file.isEmpty()) {
            return new ApiResponseMe(400, "文件为空", null);
        }
        try {
            ParseExcelUtil parseExcelUtil = new ParseExcelUtil();
            // 解析 Excel 文件
            List<Sign_inRequest> dataList = parseExcelUtil.parseExcel(file.getInputStream());
            for (Sign_inRequest data : dataList) {
                System.out.println("姓名: " + data.getReal_name());
                System.out.println("用户名: " + data.getUsername());
                System.out.println("学号: " + data.getSchool_number());
                System.out.println("密码: " + data.getPassword());
                System.out.println("角色: " + data.getRole());
                System.out.println("-------------------------");
            }
            System.out.println("解析到的数据: " + dataList.size());

            result = userService.batchInsertion(dataList, classId);
            return ApiResponseMe.shape(result, "批量导入成功");
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.shape(result, "文件解析失败");
        }
    }

    /**
     * 更新用户信息接口
     *
     * @param userDto 用户信息对象
     * @return 返回更新结果
     */
    @Operation(summary = "更新用户信息", description = "更新用户的基本信息")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "更新成功"),
        @ApiResponse(responseCode = "400", description = "缺少用户信息"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/nerv/updateUser")
    public ApiResponseMe updateUser(
            @Parameter(description = "用户信息对象", required = true)
            @RequestBody UserDto userDto) {
        if (userDto == null) {
            throw new BusinessException(400, "缺少用户信息");
        }
        try {
            Boolean result = userService.updateUser(userDto);
            if (result) {
                return ApiResponseMe.success("修改成功");
            } else {
                return ApiResponseMe.error(400, "修改失败");
            }
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 获取学生列表接口
     *
     * @param teacherNumber 老师工号
     * @return 返回学生列表
     */
    @Operation(summary = "获取学生列表", description = "获取指定教师的所有学生列表")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "缺少老师工号"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/getStudentList")
    public ApiResponseMe getStudentList(
            @Parameter(description = "老师工号", required = true)
            @RequestParam("teacherNumber") String teacherNumber) {
        if (teacherNumber == null) {
            throw new BusinessException(400, "缺少老师工号");
        }
        try {
            UserDtoVO studentList = userService.getStudentList(teacherNumber);
            if (studentList != null) {
                return ApiResponseMe.success(studentList);
            }
            return ApiResponseMe.error(400, "该老师暂未创建班级导入学生");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 获取老师班级列表接口
     *
     * @param teacherNumber 老师工号
     * @return 返回班级列表
     */
    @Operation(summary = "获取教师班级列表", description = "获取指定教师创建的所有班级")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "缺少老师工号"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/getClassByTeacherNumber")
    public ApiResponseMe getClassByTeacherNumber(
            @Parameter(description = "老师工号", required = true)
            @RequestParam("teacherNumber") String teacherNumber) {
        if (teacherNumber == null) {
            throw new BusinessException(400, "缺少老师工号");
        }
        try {
            List<ClassInfoDto> classList = userService.getClassByTeacherNumber(teacherNumber);
            return ApiResponseMe.success(classList);
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "获取班级列表失败");
        }
    }

    /**
     * 新增学生接口
     *
     * @param request 包含学生信息
     * @return 返回新增结果
     */
    @Operation(summary = "新增学生", description = "添加单个学生到指定班级")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "添加成功"),
        @ApiResponse(responseCode = "400", description = "信息不完整"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/addStudent")
    public ApiResponseMe addStudent(
            @Parameter(description = "学生信息", required = true)
            @RequestBody AddStudentRequest request) {
        if (request == null || request.getUsername() == null || request.getPassword() == null ||
                request.getRole() == null || request.getSchool_number() == null ||
                request.getClass_id() == null || request.getReal_name() == null) {
            throw new BusinessException(400, "新增考生所需信息不完整");
        }
        try {
            Boolean result = userService.addStudent(request);
            return ApiResponseMe.shape(result, "新增考生成功");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 按班级筛选学生接口
     *
     * @param teacherNumber 老师工号
     * @param classId 班级 ID
     * @param keyword 搜索更多关键词
     * @param status 学生状态
     * @param page 页码
     * @param size 每页数量
     * @return 返回筛选结果
     */
    @Operation(summary = "按班级筛选学生", description = "根据班级、关键词和状态筛选学生")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "缺少必要参数"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/filterStudentsByClass")
    public ApiResponseMe filterStudentsByClass(
            @Parameter(description = "老师工号", required = true)
            @RequestParam("teacherNumber") String teacherNumber,
            @Parameter(description = "班级ID", required = false)
            @RequestParam(value = "classId", required = false) Integer classId,
            @Parameter(description = "搜索关键词", required = false)
            @RequestParam(value = "keyword", required = false) String keyword,
            @Parameter(description = "学生状态", required = false)
            @RequestParam(value = "status", required = false) String status,
            @Parameter(description = "页码", required = false)
            @RequestParam(value = "page", defaultValue = "0") int page,
            @Parameter(description = "每页数量", required = false)
            @RequestParam(value = "size", defaultValue = "10") int size) {
        if (teacherNumber == null) {
            throw new BusinessException(400, "缺少老师工号");
        }
        try {
            int offset = page * size;
            Map<String, Object> result = userService.filterStudentsByClass(teacherNumber, classId, keyword, status, offset, size);
            return ApiResponseMe.success(result);
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "筛选学生失败");
        }
    }

    /**
     * 删除学生接口
     *
     * @param schoolNumber 学生学号
     * @return 返回删除结果
     */
    @DeleteMapping("/deleteStudent")
    public ApiResponseMe deleteStudent(@RequestParam("schoolNumber") String schoolNumber) {
        if (schoolNumber == null) {
            throw new BusinessException(400, "缺少学号");
        }
        try {
            Boolean result = userService.deleteStudent(schoolNumber);
            return ApiResponseMe.shape(result, "删除成功");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 批量激活学生接口
     *
     * @param requestBody 包含学生学号列表
     * @return 返回激活结果
     */
    @Operation(summary = "批量激活学生", description = "批量激活被禁用的学生账号")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "激活成功"),
        @ApiResponse(responseCode = "400", description = "未选择学生"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/activateStudents")
    public ApiResponseMe activateStudents(
            @Parameter(description = "包含学生学号列表", required = true)
            @RequestBody Map<String, List<String>> requestBody) {
        List<String> schoolNumbers = requestBody.get("schoolNumbers");
        if (schoolNumbers == null || schoolNumbers.isEmpty()) {
            return ApiResponseMe.error(400, "请选择要激活的学生");
        }
        try {
            userService.activateStudents(schoolNumbers);
            return ApiResponseMe.success("激活成功");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 批量禁用学生接口
     *
     * @param requestBody 包含学生学号列表
     * @return 返回禁用结果
     */
    @Operation(summary = "批量禁用学生", description = "批量禁用学生账号")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "禁用成功"),
        @ApiResponse(responseCode = "400", description = "未选择学生"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/disableStudents")
    public ApiResponseMe disableStudents(
            @Parameter(description = "包含学生学号列表", required = true)
            @RequestBody Map<String, List<String>> requestBody) {
        List<String> schoolNumbers = requestBody.get("schoolNumbers");
        if (schoolNumbers == null || schoolNumbers.isEmpty()) {
            return ApiResponseMe.error(400, "请选择要禁用的学生");
        }
        try {
            userService.disableStudents(schoolNumbers);
            return ApiResponseMe.success("禁用成功");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 批量重置学生密码接口
     *
     * @param requestBody 包含学生学号列表和新密码
     * @return 返回重置结果
     */
    @Operation(summary = "批量重置学生密码", description = "批量重置指定学生的密码")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "重置成功"),
        @ApiResponse(responseCode = "400", description = "未选择学生或缺少新密码"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/resetStudentsPassword")
    public ApiResponseMe resetStudentsPassword(
            @Parameter(description = "包含学生学号列表和新密码", required = true)
            @RequestBody Map<String, Object> requestBody) {
        List<String> schoolNumbers = (List<String>) requestBody.get("schoolNumbers");
        String newPassword = (String) requestBody.get("newPassword");

        if (schoolNumbers == null || schoolNumbers.isEmpty() || newPassword == null) {
            return ApiResponseMe.error(400, "请选择要重置密码的学生并输入新密码");
        }
        try {
            userService.resetStudentsPassword(schoolNumbers, newPassword);
            return ApiResponseMe.success("重置密码成功");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 批量移动学生班级接口
     *
     * @param requestBody 包含学生学号列表和目标班级 ID
     * @return 返回移动结果
     */
    @Operation(summary = "批量移动学生班级", description = "将学生批量移动到指定班级")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "移动成功"),
        @ApiResponse(responseCode = "400", description = "未选择学生或缺少目标班级"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @PostMapping("/moveStudentsClass")
    public ApiResponseMe moveStudentsClass(
            @Parameter(description = "包含学生学号列表和目标班级ID", required = true)
            @RequestBody Map<String, Object> requestBody) {
        List<String> schoolNumbers = (List<String>) requestBody.get("schoolNumbers");
        Integer targetClassId = (Integer) requestBody.get("targetClassId");

        if (schoolNumbers == null || schoolNumbers.isEmpty() || targetClassId == null) {
            return ApiResponseMe.error(400, "请选择要移动的学生并选择目标班级");
        }
        try {
            userService.moveStudentsClass(schoolNumbers, targetClassId);
            return ApiResponseMe.success("移动班级成功");
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "服务器内部错误");
        }
    }

    /**
     * 获取学生班级信息接口
     *
     * @param schoolNumber 学生学号
     * @return 返回学生班级信息
     */
    @Operation(summary = "获取学生班级信息", description = "获取指定学生的班级信息")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "获取成功"),
        @ApiResponse(responseCode = "400", description = "缺少学号"),
        @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    @GetMapping("/getStudentClass")
    public ApiResponseMe getStudentClass(
            @Parameter(description = "学生学号", required = true)
            @RequestParam("schoolNumber") String schoolNumber) {
        if (schoolNumber == null) {
            return ApiResponseMe.error(400, "缺少学号");
        }
        try {
            Map<String, Object> classInfo = userService.getStudentClass(schoolNumber);
            return ApiResponseMe.success(classInfo);
        } catch (BusinessException e) {
            return ApiResponseMe.error(e.getCode(), e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "获取学生班级信息失败");
        }
    }

}